package com.td.core.obj.logic;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.LinkedList;
import java.util.List;

import com.td.core.globals.TDGlobals;
import com.td.core.messages.MessageLogic;
import com.td.core.obj.Player;
import com.td.core.obj.TDMap;
import com.td.core.obj.TDPoint;
import com.td.core.obj.tower.Tower;
import com.td.core.obj.tower.Tower1;
import com.td.core.obj.tower.Tower2;
import com.td.core.obj.tower.Tower3;
import com.td.core.obj.tower.Tower4;
import com.td.core.obj.tower.Tower5;
import com.td.core.obj.utils.PointConverter;
import com.td.core.pathfinding.AStar;
import com.td.core.pathfinding.IPathfinding;
import com.td.core.pathfinding.PathPoint;
import com.td.core.pathfinding.exception.PathNotFoundException;

public class TowerLogic {

	/**
	 * Adds tower to players tower list. First checks if it is possible
	 * @param player
	 * @param tower to add
	 * @return <b>true</b> if it is possible to add, <b>false</b> if it does not
	 */
	public static boolean addTower(Player player, Tower tower) {
		
		if(canAddTower(player, tower) && canFindPath(player, tower)) {
		
			MessageLogic.addMessage(player, "Built "+ tower.getName()  + "!");
			
			player.getTowers().add(getRightTower(tower));
			player.subGold(tower.getPrice());
			
			player.getStats().incrementBuiltTower();
			return true;		
		}
		return false;
				
	}
	
	public static boolean canFindPath(Player player, Tower tower) {
		
		IPathfinding aStar = new AStar();
		
		int[][] map = new int[TDMap.MAP_X][TDMap.MAP_Y];

		for(int i = 0 ; i < TDMap.MAP_X ; i++)
			for(int j = 0 ; j < TDMap.MAP_Y ; j++)
				map[i][j] = 0;
		
		List<Tower> towers = new ArrayList<Tower>();
		towers.addAll(player.getTowers());
		towers.add(tower);
		
		for(Tower t : towers) {
			
			int x = t.getPosition().getX();
			int y = t.getPosition().getY();
			for(int i = 0 ; i < t.getSize() ; i++)
				for(int j = 0 ; j < tower.getSize() ; j++)
					map[x + i][y + j] = IPathfinding.OBSTACLE;
			
		}
		
		PathPoint ppStart = PointConverter.toPathPoint(TDGlobals.unitStart);
		PathPoint ppTarget = PointConverter.toPathPoint(TDGlobals.unitTarget);
		
		
		LinkedList<TDPoint> path = new LinkedList<TDPoint>();
		
		try {
			for(PathPoint pathPoint :  aStar.find(ppStart, ppTarget, map))				
				path.add(PointConverter.toTDPoint(pathPoint));
		
		} catch (PathNotFoundException e) {
			
			MessageLogic.addMessage(player, "No path!");
			return false;
		}
		
		
		return true;
	}
	
	public static boolean canAddTower(Player player, Tower tower) {
		
		boolean canAdd = true;
		
		try {
					
			//warunki brzegowe mapy
			if(tower.getPosition().getX() < 0 || tower.getPosition().getX() >TDMap.MAP_X - tower.getSize())
				return false;
			
			if(tower.getPosition().getY() <  TDMap.UP_BUFFOR || tower.getPosition().getY() > TDMap.MAP_Y - TDMap.DOWN_BUFFOR - tower.getSize())
				return false;
			
			
			//kolizje z reszta wiez
			for(Tower difTower : player.getTowers())
				if(isTowersCollison(tower, difTower))
					canAdd = false;
								
			//wystarczajaca ilosc zlota
			if(player.getGold() < tower.getPrice())
				canAdd = false;
					
		} catch (ConcurrentModificationException e) {
			
			e.printStackTrace();
			canAdd = false;
		}
					
		
						
		return canAdd;
	}
	
	private static boolean isTowersCollison(Tower tower1, Tower tower2) {
		
		//Robie takie cos, bo raz po 20lvl wyskoczyl mi tu NPE, a nie umiem tego odtworzyc, zeby zdebugowac
		try {
			if ((tower1.getPosition().getX() > (tower2.getPosition().getX() + tower2.getSize() - 1)) ||
					((tower1.getPosition().getX() + tower1.getSize() - 1) < tower2.getPosition().getX())) {
				return false;
			}
			if ((tower1.getPosition().getY() > (tower2.getPosition().getY() + tower2.getSize() - 1)) ||
					((tower1.getPosition().getY() + tower1.getSize() - 1) < tower2.getPosition().getY())) {
				return false;
			}
	        return true;
	        
		} catch (Exception e) {
			
			return true;
		}
	}
	
	public static Tower getRightTower(Tower tower) {
		
		Tower newTower = null;
		if(tower instanceof Tower1)
			newTower = new Tower1(tower);
		else if(tower instanceof Tower2)
			newTower = new Tower2(tower);
		else if(tower instanceof Tower3)
			newTower = new Tower3(tower);
		else if(tower instanceof Tower4)
			newTower = new Tower4(tower);
		else if(tower instanceof Tower5)
			newTower = new Tower5(tower);
		
		return newTower;
	}
}
